package com.lhy.admin.common.treeable;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 树形对象通用接口, 工具类
 *
 * @author backflow
 * 2014年10月16日 上午10:02:51
 */
@Slf4j
public class TreeableUtil {

    /**
     * @param list               普通list
     * @param treeableChildClass treeable需要实现treeable 继承 list<T>
     * @return java.util.List<com.lhy.admin.common.treeable.Treeable>
     * @throws
     * @Title: toTree
     * @Description: 把普通list转为tree
     * @date 2018/6/7 20:28
     */
    public static <T> List<Treeable> toTree(List<T> list, Class<? extends Treeable> treeableChildClass) {
        Map<Integer, Treeable> map = list.stream()
                .map(o -> newTreeable(o, treeableChildClass))
                .collect(Collectors.toMap(Treeable::getId, t -> t, (a, b) -> b, () -> new LinkedHashMap<>(list.size())));
        return tree(map);
    }

    @SneakyThrows
    private static <T> Treeable newTreeable(T o, Class<? extends Treeable> clazz) {
        Constructor<? extends Treeable> constructor = clazz.getConstructor(o.getClass());
        return constructor.newInstance(o);
    }

    private static List<Treeable> tree(Map<? extends Integer, ? extends Treeable> map) {
        return tree(map, 0);
    }

    /**
     * 将数据封装成树形结构，无限级深，只需遍历一次
     */
    private static List<Treeable> tree(Map<? extends Integer, ? extends Treeable> map, Integer root) {
        if (map == null || map.isEmpty()) {
            return Collections.emptyList();
        }
        List<Treeable> tree = new ArrayList<>(map.size());
        for (Treeable v : map.values()) {
            Integer pid = v.getParent();
            Treeable parent = map.get(pid);
            /* || parent == null*/
            if (Objects.equals(pid, root)) {
                tree.add(v);
            } else if (parent != null) {
                parent.getChildren().add(v);
            }
        }
        return tree;
    }
}
